package com.googlecode.flair.code
{
	import com.googlecode.flair.FlairApplication;
	import com.googlecode.flair.FlairComponent;
	import com.googlecode.flair.FlairComponentNonUI;
	import com.googlecode.flair.FlairModelLocator;
	import com.googlecode.flair.IFlairComponent;
	
	import flash.utils.Dictionary;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	
	import mx.containers.Canvas;
	import mx.controls.Alert;
	
	public class MXMLCodeGenerator
	{
		
		private var cssCode : XML = null;
		private var cssText : String = "";
		
		public function MXMLCodeGenerator()
		{
		}
		
		
		/**
		 * 
		 * @param component
		 * @return 
		 * 
		 */
		public final function createCode(component : IFlairComponent) : XML 
		{
			cssCode = <Style />;
			cssText = "";
			cssCode.setNamespace(new Namespace("mx", "http://www.adobe.com/2006/mxml"));
			var xmlCode : XML = generateCode(component);
			cssCode.appendChild(new XML(cssText));
			return xmlCode;
		}
		
		
		
		private function generateCode(component : IFlairComponent) : XML 
		{
			var clasz : String = getQualifiedClassName(component.component);
			var thePackage : String = clasz.substr(0, clasz.indexOf("::"));
			var prefix : String = thePackage.substr(thePackage.lastIndexOf(".") + 1);
			var claszName : String = clasz.substr(clasz.indexOf("::") + 2);
			var code : XML = null;
			if (component.parentComponent) {
				code = <{claszName} />;
			} else {
				code = <Application />;
			}
			var codeNamespace : Namespace = null;
			if (clasz.indexOf("mx.") == 0) {
				var mxns : Namespace = new Namespace("mx", "http://www.adobe.com/2006/mxml");
				codeNamespace = mxns;
				code.setNamespace(mxns);
			} else {
				
				var ns : Namespace = new Namespace(prefix, thePackage + ".*");
				code = <{component.componentName}  />;
				codeNamespace = ns;
				code.setNamespace(ns);
			}
			
			if (component == FlairModelLocator.instance.currentComponent) {
				code.appendChild(cssCode);
			}
			
			var properties :Dictionary = component.editedProperties;
			for (var property : String in properties) {
				if (property != "componentId") {
					code.@[property] = properties[property];
				}
			}
			var styles :Dictionary = component.editedStyles;
			
			if (component.getValue("styleName")) {
				var styleName : String = component.getValue("styleName") as String;
				var cssClass : String = claszName + "." + styleName + "{\n";
				for (var style : String in styles) {
					cssClass += "\t" + style + " : ";
					var isColored : Boolean = style.toLowerCase().indexOf("color") > -1;
					if (isColored && styles[style] is uint) {
						cssClass += toColorHex(styles[style]);
					} else if (isColored && styles[style] is Array) {
						cssClass += getColorArray(styles[style] as Array);
					} else if (style.toLowerCase().indexOf("icon") > -1) {
						cssClass += getIconPath(styles[style] as Class);
					} else if (styles[style] is Array) {
						cssClass += getArray(styles[style] as Array);
					} else {
						cssClass += styles[style];
					}
					cssClass += ";\n";
				}
				cssClass += "}\n\n"
				cssText += cssClass;
			} else {
				for (style in styles) {
					isColored = style.toLowerCase().indexOf("color") > -1;
					if (isColored && styles[style] is uint) {
						code.@[style] = toColorHex(styles[style]);
					} else if (isColored && styles[style] is Array) {
						code.@[style] = "[" + getColorArray(styles[style] as Array) + "]";
					} else if (style.toLowerCase().indexOf("icon") > -1) {
						code.@[style] = getIconPath(styles[style] as Class);
					} else if (styles[style] is Array) {
						cssClass +="[" +  getArray(styles[style] as Array) + "]";
					} else {
						code.@[style] = styles[style];
					}
				}
			}
			
			var elements :Dictionary = component.editedElements;
			for each (var subComponent : IFlairComponent in component.components) {
				if (subComponent is FlairComponentNonUI) {
					var nonUi : FlairComponentNonUI = FlairComponentNonUI(subComponent);
					var element : String = nonUi.property;
					var elementCode : XML = code.child(element)[0];
					if (!elementCode) {
						elementCode = <{element} />;
						elementCode.setNamespace(codeNamespace);
						code.appendChild(elementCode);
					}
					elementCode.appendChild(generateCode(subComponent));
				} else {
					code.appendChild(generateCode(subComponent));
				}
			}
			return code;
		}
		
		/**
		 * 
		 * @param colors
		 * @return 
		 * 
		 */
		private function getColorArray(colors : Array) : String {
			var textValue : String = "";
			for (var indx : int = 0; indx < colors.length; indx++) {
				if (indx > 0) {
					textValue+=", ";
				}
				textValue += toColorHex(colors[indx]);
			}
			return textValue ;
		} 
		
		
		private function getArray(values : Array) : String {
			var textValue : String = "";
			for (var indx : int = 0; indx < values.length; indx++) {
				if (indx > 0) {
					textValue+=", ";
				}
				textValue += values[indx];
			}
			return textValue ;
		}
		
		/**
		 * 
		 * @param value
		 * @return 
		 * 
		 */
		private function toColorHex(value : Object) : String {
			var text : String = Number(value).toString(16);
			while (text.length < 6) {
				text = "0" + text;
			}
			return '#' + text.toUpperCase();
		}
		
		
		private function getIconPath(icon : Class) : String {
			var className : String = getQualifiedClassName(icon);
			var iconName : String = className.substring(className.indexOf("::") + 2);
			return "@Embed(source='/assets/icons/" + iconName + ".png')";
		}
		
		 
		
		/**
		 * 
		 * @param code
		 * 
		 */
		public final function loadCode(code : String) : void 
		{
			try {
				var xmlCode : XML = new XML(code);
				if (xmlCode.localName() != "Application") {
					return;
				}
				loadFromXml(xmlCode);
				FlairApplication.instance.application.defaultView.validateSize(true);
			} catch (error : Error) {
				Alert.show(error.message);
			}
		}
		
		/**
		 * 
		 * @param xmlCode
		 * @return 
		 * 
		 */
		private function loadFromXml (xmlCode : XML, parent : IFlairComponent = null) : void {
			var className : String = xmlCode.localName() as String;
			var component : FlairComponent = null;
			if (className == "Application") {
				FlairApplication.instance.application.defaultView.removeAllChildren();
				component = new FlairComponent(FlairApplication.instance.application.defaultView);
				FlairModelLocator.instance.rootComponent = component;
			} else {
				var clasz : Class = Canvas;
				try {
					clasz = getDefinitionByName("mx.containers::" + className) as Class;
				} catch (e1 : Error) {
					clasz = getDefinitionByName("mx.controls::" + className) as Class;
				}
				component = new FlairComponent(new clasz());
				parent.add(component);
			}
			var attributes : XMLList = xmlCode.attributes();
			for each (var attribute : XML in attributes) {
				var name : String = String(attribute.localName());
				var isColored : Boolean = name.toLowerCase().indexOf("color") > -1;
				var value : String = attribute.toString();
				if (isColored && value.charAt(0) == '[') {
					var colors : Array = value.substr(1, value.length - 2).split(", ");
					var theColors : Array = [];
					for each (var color : String in colors) {
						theColors.push(Number(color.replace("#", '0x')));
					}
					component.putValue(name, theColors);
				} else if (isColored && value.charAt(0) == '#') {
					var theColor : Number = Number(value.replace("#", '0x'));
					component.putValue(name, theColor);
				} else if (name.toLowerCase().indexOf("icon") > -1) {
					var theIcon : Class = readIcon(value);
					component.putValue(name, theIcon);
				} else {
					component.putValue(name, value);
				}
			}
			var children : XMLList = xmlCode.children();
			for each (var child : XML in children) {
				loadFromXml(child, component);
			}
		}
		
		
		private function readIcon(path : String) : Class {
			var name : String = path.substring(path.indexOf("icons/") + 6,path.indexOf("."));
			try {
				return getDefinitionByName("com.googlecode.flair.icons::" + name) as Class;
			} catch (error : Error) {
			}
			return null;
		}

	}
}